package jun.svr.newSocket;

import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import jun.comm.netkit.JunProtocol;

public class NIOServerSocket {
	
	//存储SelectionKey的队列
    private static List<SelectionKey> writeQueen = new ArrayList<SelectionKey>();
    private static Selector selector = null;
	ServerSocketChannel svrSktChan = null;

	// 监听IP地址
	private static String IP = "127.0.0.1";

	// 监听端口
	private static int PORT = 50080;

    //添加SelectionKey到队列
    public static void addWriteQueen(SelectionKey key){
        synchronized (writeQueen) {
        	if(selector!=null){
        		writeQueen.add(key);
        		//唤醒主线程
        		selector.wakeup();
        	}
        }
    }
    
    public static void addWriteQueen(){
        selector.wakeup();
    }

	public void init() {
		try {
			// 打开监听信道
			svrSktChan = ServerSocketChannel.open();
			
			// 绑定地址跟端口
			svrSktChan.socket().bind(new InetSocketAddress(IP, PORT));

			// 设置为非阻塞模式
			svrSktChan.configureBlocking(false);

			// 创建选择器
			selector = Selector.open();

			// 将选择器绑定到监听信道,只有非阻塞信道才可以注册选择器.并在注册过程中指出该信道可以进行Accept操作
			svrSktChan.register(selector, SelectionKey.OP_ACCEPT);

			System.out.println("UserSvr服务启动成功，端口:" + PORT);
			System.out.println("等待客户端连接...");
		} catch (Exception e) {
			System.out.println("SVR初始化出错");
		}
	}
	
	public void run() throws Exception {
		if (selector.isOpen()) {
			 while (true) {
	            // 获取可用I/O通道,获得有多少可用的通道
	            int num = selector.select();
	            // 判断是否存在可用的通道
	            if (num > 0) {
					
	            	// 创建一个处理协议的实现类,由它来具体操作
					JunProtocol junProtocol = null;
	            	
					// 取得迭代器.selectedKeys()中包含了每个准备好某一I/O操作的信道的SelectionKey
					Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();
	            	
	                // 迭代遍历当前I/O通道
	                while (keyIter.hasNext()) {
	                    // 获得当前key
	                    SelectionKey key = keyIter.next();
	                    
						try {
							if (key.isAcceptable()) {
								junProtocol = new JunProtocol();
								// 有客户端连接请求时
								junProtocol.accept(key);
							}
							
							if (key.isReadable()) {
								junProtocol = new JunProtocol();
								// 从客户端读取数据
								junProtocol.read(key);
								
								// 将写操作添加到队列中
			                    NIOServerSocket.addWriteQueen(key);
							}
							
							if (key.isValid() && key.isWritable()) {
								junProtocol = new JunProtocol();
								junProtocol.cont = "这里是svr端返回的数据";
								// 客户端可写时
								junProtocol.write(key);
							}
						} catch (Exception e) {
							System.out.println(e);
						}finally {
							 // 移除处理过的键(调用iterator的remove()方法，并不是移除当前I/O通道，标识当前I/O通道已经处理。)
							keyIter.remove();
						}
	                }
	            }else{
	                synchronized (writeQueen) {
	                    while(writeQueen.size() > 0){
	                        SelectionKey key = writeQueen.remove(0);
	                        //注册写事件
	                        SocketChannel channel = (SocketChannel) key.channel();
	                        channel.register(selector, SelectionKey.OP_WRITE);
	                    }
	                }
	            }
	        }
		}
	}

    public static void main(String[] args) throws Exception {
    	NIOServerSocket nIOServerSocket = new NIOServerSocket();
    	nIOServerSocket.init();
    	nIOServerSocket.run();
    }
}
